home *** CD-ROM | disk | FTP | other *** search
- /*
- * DOCUMENT.CPP
- *
- * Implementation of the CFreeloaderDoc derivation of CDocument.
- * We create a default handler object and use it for drawing, data
- * caching, and serialization.
- *
- * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
- *
- * Kraig Brockschmidt, Software Design Engineer
- * Microsoft Systems Developer Relations
- *
- * Internet : kraigb@microsoft.com
- * Compuserve: >INTERNET:kraigb@microsoft.com
- */
-
-
- #include "freeload.h"
-
-
-
- /*
- * CFreeloaderDoc::CFreeloaderDoc
- * CFreeloaderDoc::~CFreeloaderDoc
- *
- * Constructor Parameters:
- * hInst HINSTANCE of the application.
- */
-
- CFreeloaderDoc::CFreeloaderDoc(HINSTANCE hInst)
- : CDocument(hInst)
- {
- m_pIStorage=NULL;
- m_pIUnknown=NULL;
- m_dwConn=0;
- return;
- }
-
-
- CFreeloaderDoc::~CFreeloaderDoc(void)
- {
- ReleaseObject();
-
- if (NULL!=m_pIStorage)
- m_pIStorage->Release();
-
- return;
- }
-
-
-
-
- /*
- * CFreeloaderDoc::ReleaseObject
- *
- * Purpose:
- * Centralizes cleanup code for the object and its cache.
- *
- * Parameters:
- * None
- *
- * Return Value:
- * None
- */
-
- void CFreeloaderDoc::ReleaseObject(void)
- {
- LPOLECACHE pIOleCache;
- HRESULT hr;
-
- if (0!=m_dwConn)
- {
- hr=m_pIUnknown->QueryInterface(IID_IOleCache
- , (LPVOID FAR *)&pIOleCache);
-
- if (SUCCEEDED(hr))
- {
- pIOleCache->Uncache(m_dwConn);
- pIOleCache->Release();
- }
- }
-
- if (NULL!=m_pIUnknown)
- m_pIUnknown->Release();
-
- CoFreeUnusedLibraries();
-
- m_dwConn=0;
- m_pIUnknown=NULL;
- return;
- }
-
-
-
-
-
- /*
- * CFreeloaderDoc::FMessageHook
- *
- * Purpose:
- * Processes WM_PAINT for the document so we can draw the object.
- *
- * Parameters:
- * <WndProc Parameters>
- * pLRes LRESULT FAR * in which to store the return value
- * for the message.
- *
- * Return Value:
- * BOOL TRUE to prevent further processing, FALSE otherwise.
- */
-
- BOOL CFreeloaderDoc::FMessageHook(HWND hWnd, UINT iMsg, WPARAM wParam
- , LPARAM lParam, LRESULT FAR *pLRes)
- {
- PAINTSTRUCT ps;
- HDC hDC;
- RECT rc;
- RECTL rcl;
- LPVIEWOBJECT pIViewObject;
- HRESULT hr;
-
- if (WM_PAINT!=iMsg)
- return FALSE;
-
- hDC=BeginPaint(hWnd, &ps);
- GetClientRect(hWnd, &rc);
-
- /*
- * To draw the object we can either QueryInterface for an IViewObject,
- * call IViewObject::Draw, and IViewObject::Release, or we can use
- * OleDraw which does exactly the same three steps, only calling
- * ::Draw with defaults. OleDraw does exactly what is done here.
- */
-
- if (NULL!=m_pIUnknown)
- {
- hr=m_pIUnknown->QueryInterface(IID_IViewObject
- , (LPVOID FAR *)&pIViewObject);
-
- if (SUCCEEDED(hr))
- {
- #ifndef WIN32
- rcl.left =MAKELONG(rc.left, 0);
- rcl.right =MAKELONG(rc.right, 0);
- rcl.top =MAKELONG(rc.top, 0);
- rcl.bottom=MAKELONG(rc.bottom, 0);
- #else
- //Win32 rectangles are already LONGs.
- rcl=rc;
- #endif
-
- pIViewObject->Draw(DVASPECT_CONTENT, -1, NULL, NULL, 0, hDC
- , &rcl, NULL, NULL, 0);
- pIViewObject->Release();
- }
- }
-
- EndPaint(hWnd, &ps);
-
- return FALSE;
- }
-
-
-
-
-
-
-
- /*
- * CFreeloaderDoc::ULoad
- *
- * Purpose:
- * Loads a given document without any user interface overwriting the
- * previous contents of the Polyline window. We do this by opening
- * the file and telling the Polyline to load itself from that file.
- *
- * Parameters:
- * fChangeFile BOOL indicating if we're to update the window title
- * and the filename from using this file.
- * pszFile LPSTR to the filename to load, NULL if the file is
- * new and untitled.
- *
- * Return Value:
- * UINT An error value from DOCERR_*
- */
-
- UINT CFreeloaderDoc::ULoad(BOOL fChangeFile, LPSTR pszFile)
- {
- HRESULT hr;
- CLSID clsID;
- LPSTORAGE pIStorage;
- LPUNKNOWN pIUnknown;
- LPPERSISTSTORAGE pIPersistStorage;
- DWORD dwMode=STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
-
- if (NULL==pszFile)
- {
- //Create a new temp file.
- hr=StgCreateDocfile(NULL, dwMode | STGM_CREATE | STGM_DELETEONRELEASE
- , 0, &pIStorage);
-
- if (FAILED(hr))
- return DOCERR_COULDNOTOPEN;
-
- m_pIStorage=pIStorage;
-
- FDirtySet(FALSE);
- Rename(NULL);
- return DOCERR_NONE;
- }
-
- //Attempt to open the storage.
- hr=StgOpenStorage(pszFile, NULL, dwMode, NULL, 0, &pIStorage);
-
- if (FAILED(hr))
- return DOCERR_COULDNOTOPEN;
-
- /*
- * When we previously called IPersistStorage::Save, OLE2.DLL kindly
- * placed a CLSID into the IStorage for us, either CLSID_StaticMetafile,
- * known to us as CLSID_FreeMetafile, or CLSID_StaticDib, known to us
- * as CLSID_FreeDib. All we have to do is load this CLSID,
- * create the object for that ID (using CoCreateInstance, see ::FPaste
- * below).
- */
-
- hr=ReadClassStg(pIStorage, &clsID);
-
- //See if we know about it.
- if (FAILED(hr) || !(IsEqualCLSID(clsID, CLSID_FreeMetafile)
- || IsEqualCLSID(clsID, CLSID_FreeDib)))
- {
- pIStorage->Release();
- return DOCERR_READFAILURE;
- }
-
- //Go create an object, then tell *it* to load the data.
- hr=CoCreateInstance(clsID, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown
- , (LPVOID FAR *)&pIUnknown);
-
- if (FAILED(hr))
- {
- pIStorage->Release();
- return DOCERR_READFAILURE;
- }
-
- //Get IPersistStorage for the data we hold.
- pIUnknown->QueryInterface(IID_IPersistStorage, (LPVOID FAR *)&pIPersistStorage);
-
- hr=pIPersistStorage->Load(pIStorage);
- pIPersistStorage->Release();
-
- if (FAILED(hr))
- {
- pIUnknown->Release();
- pIStorage->Release();
- return DOCERR_READFAILURE;
- }
-
- m_pIStorage=pIStorage;
- m_pIUnknown=pIUnknown;
-
- Rename(pszFile);
- FDirtySet(FALSE);
- return DOCERR_NONE;
- }
-
-
-
-
-
-
-
- /*
- * CFreeloaderDoc::USave
- *
- * Purpose:
- * Writes the file to a known filename, requiring that the user has
- * previously used FileOpen or FileSaveAs in order to have a filename.
- *
- * Parameters:
- * uType UINT indicating the type of file the user requested
- * to save in the File Save As dialog.
- * pszFile LPSTR under which to save. If NULL, use the current name.
- *
- * Return Value:
- * UINT An error value from DOCERR_*
- */
-
- UINT CFreeloaderDoc::USave(UINT uType, LPSTR pszFile)
- {
- HRESULT hr;
- LPSTORAGE pIStorage;
- LPPERSISTSTORAGE pIPersistStorage;
- CLSID clsID;
-
- //If we have no data object, there's nothing to save.
- if (NULL==m_pIUnknown)
- return DOCERR_WRITEFAILURE;
-
- //Get IPersistStorage for the data we hold.
- hr=m_pIUnknown->QueryInterface(IID_IPersistStorage, (LPVOID FAR *)&pIPersistStorage);
-
- if (FAILED(hr))
- return DOCERR_WRITEFAILURE;
-
- //Save or Save As with the same file is just a commit.
- if (NULL==pszFile || (NULL!=pszFile && 0==lstrcmpi(pszFile, m_szFile)))
- {
- pIPersistStorage->Save(m_pIStorage, TRUE);
- m_pIStorage->Commit(STGC_ONLYIFCURRENT);
-
- pIPersistStorage->SaveCompleted(m_pIStorage);
- pIPersistStorage->Release();
-
- FDirtySet(FALSE);
- return DOCERR_NONE;
- }
-
- /*
- * When we're given a name, open the storage, creating it new if
- * it does not exist or overwriting the old one. Then ::CopyTo
- * from the current to the new, ::Commit the new, then ::Release
- * the old.
- */
-
- hr=StgCreateDocfile(pszFile, STGM_TRANSACTED | STGM_READWRITE
- | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &pIStorage);
-
- if (FAILED(hr))
- return DOCERR_COULDNOTOPEN;
-
- //Insure the image is up to date, then tell it we're changing
- pIPersistStorage->Save(m_pIStorage, TRUE);
- pIPersistStorage->HandsOffStorage();
-
- //Save the class, bitmap or metafile
- pIPersistStorage->GetClassID(&clsID);
- hr=WriteClassStg(m_pIStorage, clsID);
-
- hr=m_pIStorage->CopyTo(NULL, NULL, NULL, pIStorage);
-
- if (FAILED(hr))
- {
- pIPersistStorage->SaveCompleted(m_pIStorage);
- pIPersistStorage->Release();
- pIStorage->Release();
- return DOCERR_WRITEFAILURE;
- }
-
- pIStorage->Commit(STGC_ONLYIFCURRENT);
-
- /*
- * Revert changes on the original storage. If this was a temp file,
- * it's deleted since we used STGM_DELETEONRELEASE.
- */
- m_pIStorage->Release();
-
- //Make this new storage current
- m_pIStorage=pIStorage;
- pIPersistStorage->SaveCompleted(m_pIStorage);
- pIPersistStorage->Release();
-
- Rename(pszFile);
- FDirtySet(FALSE);
- return DOCERR_NONE;
- }
-
-
-
-
-
-
- /*
- * CFreeloaderDoc::FClip
- *
- * Purpose:
- * Places a private format, a metafile, and a bitmap of the display
- * on the clipboard, optionally implementing Cut by deleting the
- * data in the current window after rendering.
- *
- * Parameters:
- * hWndFrame HWND of the main window.
- * fCut BOOL indicating cut (TRUE) or copy (FALSE).
- *
- * Return Value:
- * BOOL TRUE if successful, FALSE otherwise.
- */
-
- BOOL CFreeloaderDoc::FClip(HWND hWndFrame, BOOL fCut)
- {
- BOOL fRet=TRUE;
- static UINT rgcf[3]={CF_METAFILEPICT, CF_DIB, CF_BITMAP};
- const UINT cFormats=3;
- UINT i;
- HGLOBAL hMem;
-
- if (NULL==m_pIUnknown)
- return FALSE;
-
- if (!OpenClipboard(hWndFrame))
- return FALSE;
-
- //Clean out whatever junk is in the clipboard.
- EmptyClipboard();
-
- for (i=0; i < cFormats; i++)
- {
- hMem=RenderFormat(rgcf[i]);
-
- if (NULL!=hMem)
- {
- SetClipboardData(rgcf[i], hMem);
- fRet=TRUE;
- break;
- }
- }
-
- //Free clipboard ownership.
- CloseClipboard();
-
- //If we're cutting, clean out the cache and the object we hold.
- if (fRet && fCut)
- {
- ReleaseObject();
- InvalidateRect(m_hWnd, NULL, TRUE);
- UpdateWindow(m_hWnd);
- FDirtySet(TRUE);
- }
-
- return fRet;
- }
-
-
-
-
-
- /*
- * CFreeloaderDoc::RenderFormat
- *
- * Purpose:
- * Renders a specific clipboard format into global memory. We have this
- * function split out because we'll eventually move to delayed rendering
- * and this will then be immediately callable from the frame.
- *
- * Parameters:
- * cf UINT format to render.
- *
- * Return Value:
- * HGLOBAL Global memory handle containing the data.
- */
-
- HGLOBAL CFreeloaderDoc::RenderFormat(UINT cf)
- {
- LPDATAOBJECT pIDataObject;
- FORMATETC fe;
- STGMEDIUM stm;
-
- if (NULL==m_pIUnknown)
- return NULL;
-
- //We only have to ask the data object (cache) for the data.
- switch (cf)
- {
- case CF_METAFILEPICT:
- stm.tymed=TYMED_MFPICT;
- break;
-
- case CF_DIB:
- stm.tymed=TYMED_HGLOBAL;
- break;
-
- case CF_BITMAP:
- stm.tymed=TYMED_GDI;
- break;
-
- default:
- return NULL;
- }
-
- stm.hGlobal=NULL;
- SETFormatEtc(fe, cf, DVASPECT_CONTENT, NULL, stm.tymed, -1);
-
- m_pIUnknown->QueryInterface(IID_IDataObject, (LPVOID FAR *)&pIDataObject);
- pIDataObject->GetData(&fe, &stm);
- pIDataObject->Release();
-
- return stm.hGlobal;
- }
-
-
-
-
-
-
- /*
- * CFreeloaderDoc::FQueryPaste
- *
- * Purpose:
- * Determines if we can paste data from the clipboard.
- *
- * Parameters:
- * None
- *
- * Return Value:
- * BOOL TRUE if data is available, FALSE otherwise.
- */
-
- BOOL CFreeloaderDoc::FQueryPaste(void)
- {
- return IsClipboardFormatAvailable(CF_BITMAP)
- || IsClipboardFormatAvailable(CF_DIB)
- || IsClipboardFormatAvailable(CF_METAFILEPICT);
- }
-
-
-
-
-
- /*
- * CFreeloaderDoc::FPaste
- *
- * Purpose:
- * Retrieves the private data format from the clipboard and sets it
- * to the current figure in the editor window.
- *
- * Note that if this function is called, then the clipboard format
- * is available because the Paste menu item is only enabled if the
- * format is present.
- *
- * Parameters:
- * hWndFrame HWND of the main window.
- *
- * Return Value:
- * BOOL TRUE if successful, FALSE otherwise.
- */
-
- BOOL CFreeloaderDoc::FPaste(HWND hWndFrame)
- {
- UINT cf=0;
- BOOL fRet=FALSE;
- HRESULT hr;
- DWORD dwConn;
- LPUNKNOWN pIUnknown;
- LPOLECACHE pIOleCache;
- LPPERSISTSTORAGE pIPersistStorage;
- FORMATETC fe;
- STGMEDIUM stm;
- CLSID clsID;
-
- if (!OpenClipboard(hWndFrame))
- return FALSE;
-
- /*
- * Try to get data in order of metafile, dib, bitmap. We set stm.tymed
- * up front so if we actually get something a call to ReleaseStgMedium
- * will clean it up for us.
- */
-
- stm.tymed=TYMED_MFPICT;
- stm.hGlobal=GetClipboardData(CF_METAFILEPICT);
-
- if (NULL!=stm.hGlobal)
- cf=CF_METAFILEPICT;
-
- if (0==cf)
- {
- stm.tymed=TYMED_HGLOBAL;
- stm.hGlobal=GetClipboardData(CF_DIB);
-
- if (NULL!=stm.hGlobal)
- cf=CF_DIB;
- }
-
- if (0==cf)
- {
- stm.tymed=TYMED_GDI;
- stm.hGlobal=GetClipboardData(CF_BITMAP);
-
- if (NULL!=stm.hGlobal)
- cf=CF_BITMAP;
- }
-
- CloseClipboard();
-
- //Didn't get anything? Then we're finished.
- if (0==cf)
- return FALSE;
-
- //This now describes the data we have.
- SETFormatEtc(fe, cf, DVASPECT_CONTENT, NULL, stm.tymed, -1);
-
-
- /*
- * Create an object to deal with this data. There's two ways to
- * do this: CoCreateInstance (CoGetClassObject) or
- * OleCreateDefaultHandler. The first will go through all the exercises
- * of looking up the CLSID in the regDB, finding OLE2.DLL (registered
- * for these classes), getting a class factory, and using
- * IClassFactory::CreateInstance.
- *
- * The second method directly into ole2.dll which creates an object
- * identical to that created with CoCreateInstnace. This call is more
- * terse and generally faster.
- *
- * This function always uses OleCreateDefaultHandler. For an
- * example of CoCreateInstance, see ::ULoad above.
- */
-
- if (CF_METAFILEPICT==cf)
- clsID=CLSID_FreeMetafile;
- else
- clsID=CLSID_FreeDib;
-
- hr=OleCreateDefaultHandler(clsID, NULL, IID_IUnknown, (LPVOID FAR *)&pIUnknown);
-
- if (FAILED(hr))
- {
- ReleaseStgMedium(&stm);
- return FALSE;
- }
-
- /*
- * Our contract says we provide storage through IPersistStorage::InitNew.
- * We know that the object we're dealing with supports IPersistStorage
- * and IOleCache, so we don't bother to check return values.
- * HACK: Living Dangerously?
- */
- pIUnknown->QueryInterface(IID_IPersistStorage, (LPVOID FAR *)&pIPersistStorage);
- pIPersistStorage->InitNew(m_pIStorage);
- pIPersistStorage->Release();
-
- //Now that we have the cache object, shove the data into it.
- pIUnknown->QueryInterface(IID_IOleCache, (LPVOID FAR *)&pIOleCache);
- pIOleCache->Cache(&fe, ADVF_PRIMEFIRST, &dwConn);
-
- hr=pIOleCache->SetData(&fe, &stm, TRUE);
- pIOleCache->Release();
-
- if (FAILED(hr))
- {
- ReleaseStgMedium(&stm);
- pIUnknown->Release();
- return FALSE;
- }
-
- //Now that that's all done, replace our current with the new.
- ReleaseObject();
- m_pIUnknown=pIUnknown;
- m_dwConn=dwConn;
-
- FDirtySet(TRUE);
-
- InvalidateRect(m_hWnd, NULL, TRUE);
- UpdateWindow(m_hWnd);
- return TRUE;
- }
-